/*
 * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef VIRTNET_REC_H
#define VIRTNET_REC_H

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <syslog.h>
#include "virtnet_vq.h"
#include "jsonrpc-c.h"
#include "virtnet.h"

#ifdef __cplusplus
extern "C" {
#endif

#define FILE_PATH_SIZE 64
#define STR_SIZE 64
#define RECOVERY_PATH "/opt/mellanox/mlnx_virtnet/recovery"
#define JSON_EMPTY_SIZE 4

struct virtnet_rec {
	uint16_t pf_id;
	uint16_t vf_id;
	uint8_t function_type; /* enum virtnet_dev_flag */
	char device_type[STR_SIZE];
	uint16_t bdf_raw;
	char sf_parent_device[STR_SIZE];
	uint32_t pf_num;
	uint32_t sf_num;
	uint8_t rx_mode_cmd;
	uint8_t rx_mode;
	uint8_t mac_cmd;
	uint8_t mac[ETH_ALEN];
	uint8_t **mac_table;
	uint8_t vlan_table_cmd;
	uint16_t vid;
	uint8_t announce_cmd;
	uint8_t announce;
	uint16_t mq;
};

enum rec_key {
	REC_KEY_PF_ID = 0,
	REC_KEY_VF_ID,
	REC_KEY_FUNC_TYPE,
	REC_KEY_DEV_TYPE,
	REC_KEY_BDF_RAW,
	REC_KEY_SF_PAR_DEV,
	REC_KEY_PF_NUM,
	REC_KEY_SF_NUM,
	REC_KEY_RX_MODE_CMD,
	REC_KEY_RX_MODE,
	REC_KEY_MAC_CMD,
	REC_KEY_MAC,
	REC_KEY_MAC_TABLE,
	REC_KEY_VLAN_TAB_CMD,
	REC_KEY_VID,
	REC_KEY_ANNO_CMD,
	REC_KEY_ANNO,
	REC_KEY_MQ,
};

struct file_list {
	char bdf[STR_SIZE];
	bool valid;
	SLIST_ENTRY(file_list) entry;
};

SLIST_HEAD(file_list_head, file_list);

bool virtnet_rec_file_exist(const char *file_name);
int virtnet_rec_file_create(const char *file_name);
int virtnet_rec_file_rename(const char *file_name, const char *file_name_new);
int virtnet_rec_file_del(const char *file_name);

int virtnet_rec_config_handle(const char *file_name, const enum rec_key *keys,
			      int size, const struct virtnet_rec *rec, bool save);
int virtnet_rec_str_handle(const char *file_name, enum rec_key key, const char *val,
			   bool save);
int virtnet_rec_num_handle(const char *file_name, enum rec_key key, uint32_t val,
			   bool save);

int virtnet_rec_mac_save(const char *file_name, const uint8_t *mac);
int virtnet_rec_mac_del(const char *file_name, const uint8_t *mac);
int virtnet_rec_mactable_entry_add(const char *file_name, const uint8_t *mac);
int virtnet_rec_mactable_entry_del(const char *file_name, const uint8_t *mac);

int virtnet_rec_config_load(const char *file_name, enum rec_key key,
							struct virtnet_rec *rec);
int virtnet_rec_str_load(const char *file_name, enum rec_key key, char *val);
int virtnet_rec_num_load(const char *file_name, enum rec_key key, void *val);
int virtnet_rec_mac_load(const char *file_name, uint8_t *mac);
int virtnet_rec_mactable_load(const char *file_name, uint8_t **macs);

#define virtnet_rec_config_save(a, b, c, d)                                    \
	virtnet_rec_config_handle(a, b, c, d, true)
#define virtnet_rec_pf_id_save(a, b)                                           \
	virtnet_rec_num_handle(a, REC_KEY_PF_ID, b, true)
#define virtnet_rec_vf_id_save(a, b)                                           \
	virtnet_rec_num_handle(a, REC_KEY_VF_ID, b, true)
#define virtnet_rec_function_type_save(a, b)                                   \
	virtnet_rec_num_handle(a, REC_KEY_FUNC_TYPE, b, true)
#define virtnet_rec_device_type_save(a, b)                                     \
	virtnet_rec_str_handle(a, REC_KEY_DEV_TYPE, b, true)
#define virtnet_rec_bdf_raw_save(a, b)                                         \
	virtnet_rec_num_handle(a, REC_KEY_BDF_RAW, b, true)
#define virtnet_rec_sf_parent_device_save(a, b)                                \
	virtnet_rec_str_handle(a, REC_KEY_SF_PAR_DEV, b, true)
#define virtnet_rec_pf_num_save(a, b)                                           \
	virtnet_rec_num_handle(a, REC_KEY_PF_NUM, b, true)
#define virtnet_rec_sf_num_save(a, b)                                           \
	virtnet_rec_num_handle(a, REC_KEY_SF_NUM, b, true)
#define virtnet_rec_rx_mode_cmd_save(a, b)                                     \
	virtnet_rec_num_handle(a, REC_KEY_RX_MODE_CMD, b, true)
#define virtnet_rec_rx_mode_save(a, b)                                         \
	virtnet_rec_num_handle(a, REC_KEY_RX_MODE, b, true)
#define virtnet_rec_mac_cmd_save(a, b)                                         \
	virtnet_rec_num_handle(a, REC_KEY_MAC_CMD, b, true)
#define virtnet_rec_vlan_table_cmd_save(a, b)                                  \
	virtnet_rec_num_handle(a, REC_KEY_VLAN_TAB_CMD, b, true)
#define virtnet_rec_vid_save(a, b)                                             \
	virtnet_rec_num_handle(a, REC_KEY_VID, b, true)
#define virtnet_rec_announce_cmd_save(a, b)                                    \
	virtnet_rec_num_handle(a, REC_KEY_ANNO_CMD, b, true)
#define virtnet_rec_announce_save(a, b)                                        \
	virtnet_rec_num_handle(a, REC_KEY_ANNO, b, true)
#define virtnet_rec_mq_save(a, b) virtnet_rec_num_handle(a, REC_KEY_MQ, b, true)

#define virtnet_rec_config_del(a, b, c, d)                                     \
	virtnet_rec_config_handle(a, b, c, d, false)
#define virtnet_rec_pf_id_del(a, b)                                            \
	virtnet_rec_num_handle(a, REC_KEY_PF_ID, b, false)
#define virtnet_rec_vf_id_del(a, b)                                            \
	virtnet_rec_num_handle(a, REC_KEY_VF_ID, b, false)
#define virtnet_rec_function_type_del(a, b)                                    \
	virtnet_rec_num_handle(a, REC_KEY_FUNC_TYPE, b, false)
#define virtnet_rec_device_type_del(a, b)                                      \
	virtnet_rec_str_handle(a, REC_KEY_DEV_TYPE, b, false)
#define virtnet_rec_bdf_raw_del(a, b)                                          \
	virtnet_rec_num_handle(a, REC_KEY_BDF_RAW, b, false)
#define virtnet_rec_sf_parent_device_del(a, b)                                 \
	virtnet_rec_str_handle(a, REC_KEY_SF_PAR_DEV, b, false)
#define virtnet_rec_pf_num_del(a, b)                                            \
	virtnet_rec_num_handle(a, REC_KEY_PF_NUM, b, false)
#define virtnet_rec_sf_num_del(a, b)                                            \
	virtnet_rec_num_handle(a, REC_KEY_SF_NUM, b, false)
#define virtnet_rec_rx_mode_cmd_del(a, b)                                      \
	virtnet_rec_num_handle(a, REC_KEY_RX_MODE_CMD, b, false)
#define virtnet_rec_rx_mode_del(a, b)                                          \
	virtnet_rec_num_handle(a, REC_KEY_RX_MODE, b, false)
#define virtnet_rec_mac_cmd_del(a, b)                                          \
	virtnet_rec_num_handle(a, REC_KEY_MAC_CMD, b, false)
#define virtnet_rec_vlan_table_cmd_del(a, b)                                   \
	virtnet_rec_num_handle(a, REC_KEY_VLAN_TAB_CMD, b, false)
#define virtnet_rec_vid_del(a, b)                                              \
	virtnet_rec_num_handle(a, REC_KEY_VID, b, false)
#define virtnet_rec_announce_cmd_del(a, b)                                     \
	virtnet_rec_num_handle(a, REC_KEY_ANNO_CMD, b, false)
#define virtnet_rec_announce_del(a, b)                                         \
	virtnet_rec_num_handle(a, REC_KEY_ANNO, b, false)
#define virtnet_rec_mq_del(a, b) virtnet_rec_num_handle(a, REC_KEY_MQ, b, false)

#define virtnet_rec_pf_id_load(a, b) virtnet_rec_num_load(a, REC_KEY_PF_ID, b)
#define virtnet_rec_vf_id_load(a, b) virtnet_rec_num_load(a, REC_KEY_VF_ID, b)
#define virtnet_rec_function_type_load(a, b)                                   \
	virtnet_rec_num_load(a, REC_KEY_FUNC_TYPE, b)
#define virtnet_rec_device_type_load(a, b)                                     \
	virtnet_rec_str_load(a, REC_KEY_DEV_TYPE, b)
#define virtnet_rec_bdf_raw_load(a, b)                                         \
	virtnet_rec_num_load(a, REC_KEY_BDF_RAW, b)
#define virtnet_rec_sf_parent_device_load(a, b)                                \
	virtnet_rec_str_load(a, REC_KEY_SF_PAR_DEV, b)
#define virtnet_rec_pf_num_load(a, b) virtnet_rec_num_load(a, REC_KEY_PF_NUM, b)
#define virtnet_rec_sf_num_load(a, b) virtnet_rec_num_load(a, REC_KEY_SF_NUM, b)
#define virtnet_rec_rx_mode_cmd_load(a, b)                                     \
	virtnet_rec_num_load(a, REC_KEY_RX_MODE_CMD, b)
#define virtnet_rec_rx_mode_load(a, b)                                         \
	virtnet_rec_num_load(a, REC_KEY_RX_MODE, b)
#define virtnet_rec_mac_cmd_load(a, b)                                         \
	virtnet_rec_num_load(a, REC_KEY_MAC_CMD, b)
#define virtnet_rec_vlan_table_cmd_load(a, b)                                  \
	virtnet_rec_num_load(a, REC_KEY_VLAN_TAB_CMD, b)
#define virtnet_rec_vid_load(a, b) virtnet_rec_num_load(a, REC_KEY_VID, b)
#define virtnet_rec_announce_cmd_load(a, b)                                    \
	virtnet_rec_num_load(a, REC_KEY_ANNO_CMD, b)
#define virtnet_rec_announce_load(a, b) virtnet_rec_num_load(a, REC_KEY_ANNO, b)
#define virtnet_rec_mq_load(a, b) virtnet_rec_num_load(a, REC_KEY_MQ, b)

bool virtnet_device_is_recovering(struct virtnet_device *dev);
void virtnet_device_check_recover(struct virtnet_device *dev);

int virtnet_device_rxmode_recover(struct virtnet_device *dev);
int virtnet_device_mq_recover(struct virtnet_device *dev);
int virtnet_device_mac_recover(struct virtnet_device *dev);
void virtnet_device_devtype_recover(struct virtnet_device *dev);
int virtnet_device_rec_init(struct virtnet_device *dev);
int virtnet_device_rec_destroy(struct virtnet_device *dev);
int virtnet_device_rxmode_save(struct virtnet_device *dev, uint8_t rxmode);
int virtnet_device_mac_save(struct virtnet_device *dev, uint8_t *mac_octet);
int virtnet_device_mq_save(struct virtnet_device *dev, uint8_t mq);

int virtnet_device_queue_index_recover(const struct virtnet_device *dev,
					int num_eth_queues, bool ctrl_queue,
					uint16_t ctrl_queue_idx);

int virtnet_rec_sf_cleanup(struct virtnet_port_ctx *port_ctx);
int virtnet_device_sf_recover(struct virtnet_device *dev, uint32_t *pf_num,
								uint32_t *sf_num);
int virtnet_device_sf_save(struct virtnet_device *dev, uint32_t pf_num,
								uint32_t sf_num);
void virtnet_device_dump_all_rec_files(void);
void virtnet_device_mark_rec_file(struct virtnet_device *dev);
void virtnet_device_cleanup_unused_rec_files(void);

#ifdef __cplusplus
}
#endif

#endif
